Hook Modifier: add falloff & radius options

- Add falloff types & curves (matching warp-modifier)
- Add uniform scale option,
  important when adding hooks to non-uniform scaled objects,
  especially for use with lattice objects which can't avoid uneven scaling.

  This uses relative transformation set when the hook is assigned,
  when measuring the distances.
This commit is contained in:
Campbell Barton 2015-02-04 07:04:21 +11:00
parent a66a54c06d
commit c69458985c
7 changed files with 275 additions and 82 deletions

View File

@ -352,6 +352,7 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
layout.label(text="Settings are inside the Physics tab")
def HOOK(self, layout, ob, md):
use_falloff = (md.falloff_type != 'NONE')
split = layout.split()
col = split.column()
@ -366,19 +367,28 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel):
layout.separator()
row = layout.row(align=True)
if use_falloff:
row.prop(md, "falloff_radius")
row.prop(md, "strength", slider=True)
layout.prop(md, "falloff_type")
col = layout.column()
if use_falloff:
if md.falloff_type == 'CURVE':
col.template_curve_mapping(md, "falloff_curve")
split = layout.split()
col = split.column()
col.prop(md, "falloff")
col.prop(md, "force", slider=True)
col = split.column()
col.operator("object.hook_reset", text="Reset")
col.operator("object.hook_recenter", text="Recenter")
col.prop(md, "use_falloff_uniform")
if ob.mode == 'EDIT':
layout.separator()
row = layout.row()
row = col.row(align=True)
row.operator("object.hook_reset", text="Reset")
row.operator("object.hook_recenter", text="Recenter")
row = layout.row(align=True)
row.operator("object.hook_select", text="Select")
row.operator("object.hook_assign", text="Assign")

View File

@ -4840,6 +4840,11 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
if (fd->flags & FD_FLAGS_SWITCH_ENDIAN) {
BLI_endian_switch_int32_array(hmd->indexar, hmd->totindex);
}
hmd->curfalloff = newdataadr(fd, hmd->curfalloff);
if (hmd->curfalloff) {
direct_link_curvemapping(fd, hmd->curfalloff);
}
}
else if (md->type == eModifierType_ParticleSystem) {
ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md;

View File

@ -519,6 +519,20 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main)
}
}
if (!DNA_struct_elem_find(fd->filesdna, "HookModifierData", "char", "flag")) {
Object *ob;
for (ob = main->object.first; ob; ob = ob->id.next) {
ModifierData *md;
for (md = ob->modifiers.first; md; md = md->next) {
if (md->type == eModifierType_Hook) {
HookModifierData *hmd = (HookModifierData *)md;
hmd->falloff_type = eHook_Falloff_InvSquare;
}
}
}
}
if (!MAIN_VERSION_ATLEAST(main, 273, 3)) {
ParticleSettings *part;
for (part = main->particle.first; part; part = part->id.next) {

View File

@ -1485,6 +1485,10 @@ static void write_modifiers(WriteData *wd, ListBase *modbase)
if (md->type==eModifierType_Hook) {
HookModifierData *hmd = (HookModifierData*) md;
if (hmd->curfalloff) {
write_curvemapping(wd, hmd->curfalloff);
}
writedata(wd, DATA, sizeof(int)*hmd->totindex, hmd->indexar);
}
else if (md->type==eModifierType_Cloth) {

View File

@ -535,16 +535,39 @@ typedef struct ArmatureModifierData {
char defgrp_name[64]; /* MAX_VGROUP_NAME */
} ArmatureModifierData;
enum {
MOD_HOOK_UNIFORM_SPACE = (1 << 0),
};
/* same as WarpModifierFalloff */
typedef enum {
eHook_Falloff_None = 0,
eHook_Falloff_Curve = 1,
eHook_Falloff_Sharp = 2, /* PROP_SHARP */
eHook_Falloff_Smooth = 3, /* PROP_SMOOTH */
eHook_Falloff_Root = 4, /* PROP_ROOT */
eHook_Falloff_Linear = 5, /* PROP_LIN */
eHook_Falloff_Const = 6, /* PROP_CONST */
eHook_Falloff_Sphere = 7, /* PROP_SPHERE */
eHook_Falloff_InvSquare = 8, /* PROP_INVSQUARE */
/* PROP_RANDOM not used */
} HookModifierFalloff;
typedef struct HookModifierData {
ModifierData modifier;
struct Object *object;
char subtarget[64]; /* optional name of bone target, MAX_ID_NAME-2 */
char flag;
char falloff_type; /* use enums from WarpModifier (exact same functionality) */
char pad[6];
float parentinv[4][4]; /* matrix making current transform unmodified */
float cent[3]; /* visualization of hook */
float falloff; /* if not zero, falloff is distance where influence zero */
struct CurveMapping *curfalloff;
int *indexar; /* if NULL, it's using vertexgroup */
int totindex;
float force;

View File

@ -134,6 +134,22 @@ EnumPropertyItem modifier_triangulate_ngon_method_items[] = {
{0, NULL, 0, NULL, NULL}
};
#ifndef RNA_RUNTIME
/* use eWarp_Falloff_*** & eHook_Falloff_***, they're in sync */
static EnumPropertyItem modifier_warp_falloff_items[] = {
{eWarp_Falloff_None, "NONE", 0, "No Falloff", ""},
{eWarp_Falloff_Curve, "CURVE", 0, "Curve", ""},
{eWarp_Falloff_Smooth, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
{eWarp_Falloff_Sphere, "SPHERE", ICON_SPHERECURVE, "Sphere", ""},
{eWarp_Falloff_Root, "ROOT", ICON_ROOTCURVE, "Root", ""},
{eWarp_Falloff_InvSquare, "INVERSE_SQUARE", ICON_ROOTCURVE, "Inverse Square", ""},
{eWarp_Falloff_Sharp, "SHARP", ICON_SHARPCURVE, "Sharp", ""},
{eWarp_Falloff_Linear, "LINEAR", ICON_LINCURVE, "Linear", ""},
{eWarp_Falloff_Const, "CONSTANT", ICON_NOCURVE, "Constant", ""},
{0, NULL, 0, NULL, NULL}
};
#endif
/* ***** Data Transfer ***** */
EnumPropertyItem DT_method_vertex_items[] = {
@ -1111,19 +1127,6 @@ static void rna_def_modifier_warp(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
static EnumPropertyItem prop_falloff_items[] = {
{eWarp_Falloff_None, "NONE", 0, "No Falloff", ""},
{eWarp_Falloff_Curve, "CURVE", 0, "Curve", ""},
{eWarp_Falloff_Smooth, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""},
{eWarp_Falloff_Sphere, "SPHERE", ICON_SPHERECURVE, "Sphere", ""},
{eWarp_Falloff_Root, "ROOT", ICON_ROOTCURVE, "Root", ""},
{eWarp_Falloff_InvSquare, "INVERSE_SQUARE", ICON_ROOTCURVE, "Inverse Square", ""},
{eWarp_Falloff_Sharp, "SHARP", ICON_SHARPCURVE, "Sharp", ""},
{eWarp_Falloff_Linear, "LINEAR", ICON_LINCURVE, "Linear", ""},
{eWarp_Falloff_Const, "CONSTANT", ICON_NOCURVE, "Constant", ""},
{0, NULL, 0, NULL, NULL}
};
srna = RNA_def_struct(brna, "WarpModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Warp Modifier", "Warp modifier");
RNA_def_struct_sdna(srna, "WarpModifierData");
@ -1146,7 +1149,7 @@ static void rna_def_modifier_warp(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "falloff_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, prop_falloff_items);
RNA_def_property_enum_items(prop, modifier_warp_falloff_items);
RNA_def_property_ui_text(prop, "Falloff Type", "");
RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@ -1678,15 +1681,28 @@ static void rna_def_modifier_hook(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "HookModifierData");
RNA_def_struct_ui_icon(srna, ICON_HOOK);
prop = RNA_def_property(srna, "falloff", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 100, 100, 2);
RNA_def_property_ui_text(prop, "Falloff", "If not zero, the distance from the hook where influence ends");
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "force");
RNA_def_property_range(prop, 0, 1);
RNA_def_property_ui_text(prop, "Strength", "Relative force of the hook");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "force", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, 0, 1);
RNA_def_property_ui_text(prop, "Force", "Relative force of the hook");
prop = RNA_def_property(srna, "falloff_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_items(prop, modifier_warp_falloff_items); /* share the enum */
RNA_def_property_ui_text(prop, "Falloff Type", "");
RNA_def_property_translation_context(prop, BLF_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "falloff_radius", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "falloff");
RNA_def_property_range(prop, 0, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 100, 100, 2);
RNA_def_property_ui_text(prop, "Radius", "If not zero, the distance from the hook where influence ends");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "falloff_curve", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "curfalloff");
RNA_def_property_ui_text(prop, "Falloff Curve", "Custom Lamp Falloff Curve");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "center", PROP_FLOAT, PROP_NONE);
@ -1706,6 +1722,11 @@ static void rna_def_modifier_hook(BlenderRNA *brna)
"Name of Parent Bone for hook (if applicable), also recalculates and clears offset");
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "use_falloff_uniform", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_HOOK_UNIFORM_SPACE);
RNA_def_property_ui_text(prop, "Uniform Falloff", "Compensate for non-uniform object scale");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
prop = RNA_def_property(srna, "vertex_group", PROP_STRING, PROP_NONE);
RNA_def_property_string_sdna(prop, NULL, "name");
RNA_def_property_ui_text(prop, "Vertex Group",

View File

@ -43,6 +43,7 @@
#include "BKE_cdderivedmesh.h"
#include "BKE_modifier.h"
#include "BKE_deform.h"
#include "BKE_colortools.h"
#include "depsgraph_private.h"
@ -55,6 +56,9 @@ static void initData(ModifierData *md)
HookModifierData *hmd = (HookModifierData *) md;
hmd->force = 1.0;
hmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
hmd->falloff_type = eHook_Falloff_Smooth;
hmd->flag = 0;
}
static void copyData(ModifierData *md, ModifierData *target)
@ -64,6 +68,8 @@ static void copyData(ModifierData *md, ModifierData *target)
modifier_copyData_generic(md, target);
thmd->curfalloff = curvemapping_copy(hmd->curfalloff);
thmd->indexar = MEM_dupallocN(hmd->indexar);
}
@ -83,6 +89,8 @@ static void freeData(ModifierData *md)
{
HookModifierData *hmd = (HookModifierData *) md;
curvemapping_free(hmd->curfalloff);
if (hmd->indexar) MEM_freeN(hmd->indexar);
}
@ -120,32 +128,172 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
static float hook_falloff(const float co_1[3], const float co_2[3], const float falloff_squared, float fac)
struct HookData_cb {
float (*vertexCos)[3];
MDeformVert *dvert;
int defgrp_index;
struct CurveMapping *curfalloff;
char falloff_type;
float falloff;
float falloff_sq;
float fac_orig;
unsigned int use_falloff : 1;
unsigned int use_uniform : 1;
float cent[3];
float mat_uniform[3][3];
float mat[4][4];
};
static float hook_falloff(
const struct HookData_cb *hd,
const float len_sq)
{
if (falloff_squared) {
float len_squared = len_squared_v3v3(co_1, co_2);
if (len_squared > falloff_squared) {
return 0.0f;
BLI_assert(hd->falloff_sq);
if (len_sq > hd->falloff_sq) {
return 0.0f;
}
else if (len_sq > 0.0f) {
float fac;
if (hd->falloff_type == eHook_Falloff_Const) {
fac = 1.0f;
goto finally;
}
else if (len_squared > 0.0f) {
return fac * (1.0f - (len_squared / falloff_squared));
else if (hd->falloff_type == eHook_Falloff_InvSquare) {
/* avoid sqrt below */
fac = 1.0f - (len_sq / hd->falloff_sq);
goto finally;
}
fac = 1.0f - (sqrtf(len_sq) / hd->falloff);
/* closely match PROP_SMOOTH and similar */
switch (hd->falloff_type) {
#if 0
case eHook_Falloff_None:
fac = 1.0f;
break;
#endif
case eHook_Falloff_Curve:
fac = curvemapping_evaluateF(hd->curfalloff, 0, fac);
break;
case eHook_Falloff_Sharp:
fac = fac * fac;
break;
case eHook_Falloff_Smooth:
fac = 3.0f * fac * fac - 2.0f * fac * fac * fac;
break;
case eHook_Falloff_Root:
fac = sqrtf(fac);
break;
case eHook_Falloff_Linear:
/* pass */
break;
#if 0
case eHook_Falloff_Const:
fac = 1.0f;
break;
#endif
case eHook_Falloff_Sphere:
fac = sqrtf(2 * fac - fac * fac);
break;
#if 0
case eHook_Falloff_InvSquare:
fac = fac * (2.0f - fac);
break;
#endif
}
finally:
return fac * hd->fac_orig;
}
else {
return hd->fac_orig;
}
}
static void hook_co_apply(struct HookData_cb *hd, const int j)
{
float *co = hd->vertexCos[j];
float fac;
if (hd->use_falloff) {
float len_sq;
if (hd->use_uniform) {
float co_uniform[3];
mul_v3_m3v3(co_uniform, hd->mat_uniform, co);
len_sq = len_squared_v3v3(hd->cent, co_uniform);
}
else {
len_sq = len_squared_v3v3(hd->cent, co);
}
fac = hook_falloff(hd, len_sq);
}
else {
fac = hd->fac_orig;
}
return fac;
if (fac) {
if (hd->dvert) {
fac *= defvert_find_weight(&hd->dvert[j], hd->defgrp_index);
}
if (fac) {
float co_tmp[3];
mul_v3_m4v3(co_tmp, hd->mat, co);
interp_v3_v3v3(co, co, co_tmp, fac);
}
}
}
static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm,
float (*vertexCos)[3], int numVerts)
{
bPoseChannel *pchan = BKE_pose_channel_find_name(hmd->object->pose, hmd->subtarget);
float vec[3], mat[4][4], dmat[4][4];
float dmat[4][4];
int i, *index_pt;
const float falloff_squared = hmd->falloff * hmd->falloff; /* for faster comparisons */
MDeformVert *dvert;
int defgrp_index, max_dvert;
struct HookData_cb hd;
if (hmd->curfalloff == NULL) {
/* should never happen, but bad lib linking could cause it */
hmd->curfalloff = curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
}
if (hmd->curfalloff) {
curvemapping_initialize(hmd->curfalloff);
}
/* Generic data needed for applying per-vertex calculations (initialize all members) */
hd.vertexCos = vertexCos;
modifier_get_vgroup(ob, dm, hmd->name, &hd.dvert, &hd.defgrp_index);
hd.curfalloff = hmd->curfalloff;
hd.falloff_type = hmd->falloff_type;
hd.falloff = (hmd->falloff_type == eHook_Falloff_None) ? 0.0f : hmd->falloff;
hd.falloff_sq = SQUARE(hd.falloff);
hd.fac_orig = hmd->force;
hd.use_falloff = (hd.falloff_sq != 0.0f);
hd.use_uniform = (hmd->flag & MOD_HOOK_UNIFORM_SPACE) != 0;
if (hd.use_uniform) {
copy_m3_m4(hd.mat_uniform, hmd->parentinv);
mul_v3_m3v3(hd.cent, hd.mat_uniform, hmd->cent);
}
else {
unit_m3(hd.mat_uniform); /* unused */
copy_v3_v3(hd.cent, hmd->cent);
}
/* get world-space matrix of target, corrected for the space the verts are in */
if (hmd->subtarget[0] && pchan) {
/* bone target if there's a matching pose-channel */
@ -156,10 +304,9 @@ static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm,
copy_m4_m4(dmat, hmd->object->obmat);
}
invert_m4_m4(ob->imat, ob->obmat);
mul_m4_series(mat, ob->imat, dmat, hmd->parentinv);
mul_m4_series(hd.mat, ob->imat, dmat, hmd->parentinv);
/* --- done with 'hd' init --- */
modifier_get_vgroup(ob, dm, hmd->name, &dvert, &defgrp_index);
max_dvert = (dvert) ? numVerts : 0;
/* Regarding index range checking below.
*
@ -168,13 +315,11 @@ static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm,
* indices that are out of range because old blender did
* not correct them on exit editmode. - zr
*/
if (hmd->force == 0.0f) {
/* do nothing, avoid annoying checks in the loop */
}
else if (hmd->indexar) { /* vertex indices? */
const float fac_orig = hmd->force;
float fac;
const int *origindex_ar;
/* if DerivedMesh is present and has original index data, use it */
@ -185,16 +330,7 @@ static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm,
for (j = 0; j < numVerts; j++) {
if (origindex_ar[j] == *index_pt) {
float *co = vertexCos[j];
if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) {
if (dvert)
fac *= defvert_find_weight(dvert + j, defgrp_index);
if (fac) {
mul_v3_m4v3(vec, mat, co);
interp_v3_v3v3(co, co, vec, fac);
}
}
hook_co_apply(&hd, j);
}
}
}
@ -203,34 +339,14 @@ static void deformVerts_do(HookModifierData *hmd, Object *ob, DerivedMesh *dm,
else { /* missing dm or ORIGINDEX */
for (i = 0, index_pt = hmd->indexar; i < hmd->totindex; i++, index_pt++) {
if (*index_pt < numVerts) {
float *co = vertexCos[*index_pt];
if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) {
if (dvert)
fac *= defvert_find_weight(dvert + (*index_pt), defgrp_index);
if (fac) {
mul_v3_m4v3(vec, mat, co);
interp_v3_v3v3(co, co, vec, fac);
}
}
hook_co_apply(&hd, *index_pt);
}
}
}
}
else if (dvert) { /* vertex group hook */
const float fac_orig = hmd->force;
for (i = 0; i < max_dvert; i++, dvert++) {
float fac;
float *co = vertexCos[i];
if ((fac = hook_falloff(hmd->cent, co, falloff_squared, fac_orig))) {
fac *= defvert_find_weight(dvert, defgrp_index);
if (fac) {
mul_v3_m4v3(vec, mat, co);
interp_v3_v3v3(co, co, vec, fac);
}
}
else if (hd.dvert) { /* vertex group hook */
for (i = 0; i < numVerts; i++) {
hook_co_apply(&hd, i);
}
}
}