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.
This commit is contained in:
Campbell Barton 2013-09-07 12:59:16 +00:00
parent 3da3c36644
commit e492fad130
8 changed files with 111 additions and 61 deletions

View 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)

View 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

View 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

View 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 */

View 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),

View 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) {

View 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 */

View 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");
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");
}