shrink-wrap constraint, improve and remove some limitations.
authorCampbell Barton <ideasman42@gmail.com>
Sat, 7 Sep 2013 12:59:16 +0000 (12:59 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sat, 7 Sep 2013 12:59:16 +0000 (12:59 +0000)
- 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.

release/scripts/startup/bl_ui/properties_constraint.py
source/blender/blenkernel/BKE_blender.h
source/blender/blenkernel/BKE_shrinkwrap.h
source/blender/blenkernel/intern/constraint.c
source/blender/blenkernel/intern/shrinkwrap.c
source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_constraint_types.h
source/blender/makesrna/intern/rna_constraint.c

index 5bb9c151c2c76d0073143f42b8ca0cf49bb5b1a6..4ad178bc064701011f3f6e2a2e5672d95ea2d981 100644 (file)
@@ -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)
index 13fd4b2bab7fa510033ef2da959efce372333950..6507999e9db9ab8be407c589431f71870dc5203b 100644 (file)
@@ -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
index 61d82e6c60407037c7a93eb1c40773c42735df80..323a926863c04f9ea8fea096dcbc049413e557eb 100644 (file)
@@ -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
index 7b7d20a54e01ac0ccbb73b10476483aea52c4033..1f892432d80907cfb707450a31868854c7c8ad2e 100644 (file)
@@ -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 */
index b9843ad061944de850aedf43db2a534b69e777de..9bc7f4b9e2b7825fce62e58f31bad804184edeb9 100644 (file)
@@ -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),
index 0cd473fd74d31bae01286b6da6f8b787acca0ea8..af2da2361d398e76e86bf5f603496288ce8c9012 100644 (file)
@@ -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) {
index f1b7a7c3cc3e1179bb459dabbdef2176faad8919..29e49a970d88fa2f4dabfd06bdcedb342f00801d 100644 (file)
@@ -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 */
index 6a1aa37d0cc3bc0b46919b343bb5dd500651f19c..8c7857a3f0ba669d503c323800d5669416e96357 100644 (file)
@@ -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");
-       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");
+
+       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_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");
 }