Shrinkwrap Constraint: implement projection features from the modifier.

Allow raycasting in two directions and culling front or back faces.

Also implement a new Invert Cull option in both constraint and
modifier that can be used to aim for faces aligned with the project
axis direction when raycasting both ways.

Reviewers: mont29

Differential Revision: https://developer.blender.org/D3737
This commit is contained in:
Alexander Gavrilov 2018-07-08 13:47:26 +03:00
parent be0e58d980
commit e38a0b3748
8 changed files with 106 additions and 9 deletions

View File

@ -758,6 +758,15 @@ class ConstraintButtonsPanel:
split.label(text="Axis Space:")
rowsub = split.row()
rowsub.prop(con, "project_axis_space", text="")
split = layout.split(factor=0.4)
split.label(text="Face Culling:")
rowsub = split.row()
rowsub.prop(con, "cull_face", expand=True)
row = layout.row()
row.prop(con, "use_project_opposite")
rowsub = row.row()
rowsub.active = con.use_project_opposite and con.cull_face != 'OFF'
rowsub.prop(con, "use_invert_cull")
layout.prop(con, "project_limit")
def DAMPED_TRACK(self, context, layout, con):

View File

@ -848,6 +848,10 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
col.prop(md, "use_negative_direction")
col.prop(md, "use_positive_direction")
subcol = col.column()
subcol.active = md.use_negative_direction and md.cull_face != 'OFF'
subcol.prop(md, "use_invert_cull")
col = split.column()
col.label(text="Cull Faces:")
col.prop(md, "cull_face", expand=True)

View File

@ -3533,8 +3533,24 @@ static void shrinkwrap_get_tarmat(struct Depsgraph *depsgraph, bConstraint *con,
break;
}
if (BKE_shrinkwrap_project_normal(0, co, no, 0.0f, &transform, treeData.tree,
&hit, treeData.raycast_callback, &treeData) == false)
char cull_mode = scon->flag & CON_SHRINKWRAP_PROJECT_CULL_MASK;
BKE_shrinkwrap_project_normal(cull_mode, co, no, 0.0f, &transform, treeData.tree,
&hit, treeData.raycast_callback, &treeData);
if (scon->flag & CON_SHRINKWRAP_PROJECT_OPPOSITE) {
float inv_no[3];
negate_v3_v3(inv_no, no);
if ((scon->flag & CON_SHRINKWRAP_PROJECT_INVERT_CULL) && (cull_mode != 0)) {
cull_mode ^= CON_SHRINKWRAP_PROJECT_CULL_MASK;
}
BKE_shrinkwrap_project_normal(cull_mode, co, inv_no, 0.0f, &transform, treeData.tree,
&hit, treeData.raycast_callback, &treeData);
}
if (hit.index < 0)
{
fail = true;
break;

View File

@ -240,7 +240,7 @@ bool BKE_shrinkwrap_project_normal(
BLI_space_transform_invert_normal(transf, hit_tmp.no);
}
if (options & (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)) {
if (options & MOD_SHRINKWRAP_CULL_TARGET_MASK) {
/* apply backface */
const float dot = dot_v3v3(dir, hit_tmp.no);
if (((options & MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE) && dot <= 0.0f) ||
@ -341,6 +341,12 @@ static void shrinkwrap_calc_normal_projection_cb_ex(
float inv_no[3];
negate_v3_v3(inv_no, tmp_no);
char options = calc->smd->shrinkOpts;
if ((options & MOD_SHRINKWRAP_INVERT_CULL_TARGET) && (options & MOD_SHRINKWRAP_CULL_TARGET_MASK)) {
options ^= MOD_SHRINKWRAP_CULL_TARGET_MASK;
}
if (aux_tree) {
BKE_shrinkwrap_project_normal(
0, tmp_co, inv_no, 0.0,
@ -349,7 +355,7 @@ static void shrinkwrap_calc_normal_projection_cb_ex(
}
BKE_shrinkwrap_project_normal(
calc->smd->shrinkOpts, tmp_co, inv_no, 0.0,
options, tmp_co, inv_no, 0.0,
&calc->local2target, targ_tree, hit,
targ_callback, treeData);
}

View File

@ -429,7 +429,8 @@ typedef struct bShrinkwrapConstraint {
char projAxisSpace; /* space to project axis in */
float projLimit; /* distance to search */
char shrinkMode; /* inside/outside/on surface (see MOD shrinkwrap) */
char pad[3];
char flag; /* options */
char pad[2];
} bShrinkwrapConstraint;
/* Follow Track constraints */
@ -635,6 +636,21 @@ typedef enum eTrackToAxis_Modes {
TRACK_nZ = 5
} eTrackToAxis_Modes;
/* Shrinkwrap flags */
typedef enum eShrinkwrap_Flags {
/* Also raycast in the opposite direction. */
CON_SHRINKWRAP_PROJECT_OPPOSITE = (1 << 0),
/* Invert the cull mode when projecting opposite. */
CON_SHRINKWRAP_PROJECT_INVERT_CULL = (1 << 1),
/* Ignore front faces in project; same value as MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE */
CON_SHRINKWRAP_PROJECT_CULL_FRONTFACE = (1 << 3),
/* Ignore back faces in project; same value as MOD_SHRINKWRAP_CULL_TARGET_BACKFACE */
CON_SHRINKWRAP_PROJECT_CULL_BACKFACE = (1 << 4),
} eShrinkwrap_Flags;
#define CON_SHRINKWRAP_PROJECT_CULL_MASK (CON_SHRINKWRAP_PROJECT_CULL_FRONTFACE | CON_SHRINKWRAP_PROJECT_CULL_BACKFACE)
/* FollowPath flags */
typedef enum eFollowPath_Flags {
FOLLOWPATH_FOLLOW = (1<<0),

View File

@ -920,8 +920,11 @@ enum {
#endif
MOD_SHRINKWRAP_INVERT_VGROUP = (1 << 6),
MOD_SHRINKWRAP_INVERT_CULL_TARGET = (1 << 7),
};
#define MOD_SHRINKWRAP_CULL_TARGET_MASK (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)
/* Shrinkwrap->projAxis */
enum {
MOD_SHRINKWRAP_PROJECT_OVER_NORMAL = 0, /* projection over normal is used if no axis is selected */

View File

@ -396,6 +396,20 @@ static void rna_SplineIKConstraint_joint_bindings_set(PointerRNA *ptr, const flo
memcpy(ikData->points, values, ikData->numpoints * sizeof(float));
}
static int rna_ShrinkwrapConstraint_face_cull_get(PointerRNA *ptr)
{
bConstraint *con = (bConstraint *)ptr->data;
bShrinkwrapConstraint *swc = (bShrinkwrapConstraint *)con->data;
return swc->flag & CON_SHRINKWRAP_PROJECT_CULL_MASK;
}
static void rna_ShrinkwrapConstraint_face_cull_set(struct PointerRNA *ptr, int value)
{
bConstraint *con = (bConstraint *)ptr->data;
bShrinkwrapConstraint *swc = (bShrinkwrapConstraint *)con->data;
swc->flag = (swc->flag & ~CON_SHRINKWRAP_PROJECT_CULL_MASK) | value;
}
static bool rna_Constraint_cameraObject_poll(PointerRNA *ptr, PointerRNA value)
{
Object *ob = (Object *)value.data;
@ -1916,6 +1930,13 @@ static void rna_def_constraint_shrinkwrap(BlenderRNA *brna)
{0, NULL, 0, NULL, NULL}
};
static const EnumPropertyItem shrink_face_cull_items[] = {
{0, "OFF", 0, "Off", "No culling"},
{CON_SHRINKWRAP_PROJECT_CULL_FRONTFACE, "FRONT", 0, "Front", "No projection when in front of the face"},
{CON_SHRINKWRAP_PROJECT_CULL_BACKFACE, "BACK", 0, "Back", "No projection when behind the face"},
{0, NULL, 0, NULL, NULL}
};
srna = RNA_def_struct(brna, "ShrinkwrapConstraint", "Constraint");
RNA_def_struct_ui_text(srna, "Shrinkwrap Constraint", "Create constraint-based shrinkwrap relationship");
RNA_def_struct_sdna_from(srna, "bShrinkwrapConstraint", "data");
@ -1965,6 +1986,25 @@ static void rna_def_constraint_shrinkwrap(BlenderRNA *brna)
RNA_def_property_ui_range(prop, 0.0f, 100.0f, 10, 3);
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");
prop = RNA_def_property(srna, "use_project_opposite", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CON_SHRINKWRAP_PROJECT_OPPOSITE);
RNA_def_property_ui_text(prop, "Project Opposite", "Project in both specified and opposite directions");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "cull_face", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "flag");
RNA_def_property_enum_items(prop, shrink_face_cull_items);
RNA_def_property_enum_funcs(prop, "rna_ShrinkwrapConstraint_face_cull_get",
"rna_ShrinkwrapConstraint_face_cull_set", NULL);
RNA_def_property_ui_text(prop, "Face Cull",
"Stop vertices from projecting to a face on the target when facing towards/away");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
prop = RNA_def_property(srna, "use_invert_cull", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", CON_SHRINKWRAP_PROJECT_INVERT_CULL);
RNA_def_property_ui_text(prop, "Invert Cull", "When projecting in the opposite direction invert the face cull mode");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
}
static void rna_def_constraint_damped_track(BlenderRNA *brna)

View File

@ -714,15 +714,13 @@ static int rna_MultiresModifier_filepath_length(PointerRNA *ptr)
static int rna_ShrinkwrapModifier_face_cull_get(PointerRNA *ptr)
{
ShrinkwrapModifierData *swm = (ShrinkwrapModifierData *)ptr->data;
return swm->shrinkOpts & (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE);
return swm->shrinkOpts & MOD_SHRINKWRAP_CULL_TARGET_MASK;
}
static void rna_ShrinkwrapModifier_face_cull_set(struct PointerRNA *ptr, int value)
{
ShrinkwrapModifierData *swm = (ShrinkwrapModifierData *)ptr->data;
swm->shrinkOpts =
(swm->shrinkOpts & ~(MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE)) | value;
swm->shrinkOpts = (swm->shrinkOpts & ~MOD_SHRINKWRAP_CULL_TARGET_MASK) | value;
}
static bool rna_MeshDeformModifier_is_bound_get(PointerRNA *ptr)
@ -3273,6 +3271,11 @@ static void rna_def_modifier_shrinkwrap(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Positive", "Allow vertices to move in the positive direction of axis");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "use_invert_cull", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "shrinkOpts", MOD_SHRINKWRAP_INVERT_CULL_TARGET);
RNA_def_property_ui_text(prop, "Invert Cull", "When projecting in the negative direction invert the face cull mode");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "invert_vertex_group", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "shrinkOpts", MOD_SHRINKWRAP_INVERT_VGROUP);
RNA_def_property_ui_text(prop, "Invert", "Invert vertex group influence");