Animation: Remove the 'Weight Paint: Fix Deforms' operator #105237

Merged
Sybren A. Stüvel merged 2 commits from dr.sybren/blender:remove-fix-deforms into main 2023-03-02 16:58:25 +01:00
5 changed files with 0 additions and 474 deletions

View File

@ -1899,7 +1899,6 @@ url_manual_mapping = (
("bpy.ops.object.shape_key_remove*", "animation/shape_keys/shape_keys_panel.html#bpy-ops-object-shape-key-remove"),
("bpy.ops.object.shape_key_retime*", "animation/shape_keys/shape_keys_panel.html#bpy-ops-object-shape-key-retime"),
("bpy.ops.object.vertex_group_add*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-add"),
("bpy.ops.object.vertex_group_fix*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-fix"),
("bpy.ops.outliner.collection_new*", "editors/outliner/editing.html#bpy-ops-outliner-collection-new"),
("bpy.ops.outliner.show_hierarchy*", "editors/outliner/editing.html#bpy-ops-outliner-show-hierarchy"),
("bpy.ops.outliner.show_one_level*", "editors/outliner/editing.html#bpy-ops-outliner-show-one-level"),

View File

@ -3201,7 +3201,6 @@ class VIEW3D_MT_paint_weight(Menu):
props.data_type = 'VGROUP_WEIGHTS'
layout.operator("object.vertex_group_limit_total", text="Limit Total")
layout.operator("object.vertex_group_fix", text="Fix Deforms")
if not is_editmode:
layout.separator()

View File

@ -287,7 +287,6 @@ void OBJECT_OT_vertex_group_normalize(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_normalize_all(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_levels(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_lock(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_fix(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_invert(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_smooth(struct wmOperatorType *ot);
void OBJECT_OT_vertex_group_clean(struct wmOperatorType *ot);

View File

@ -208,7 +208,6 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_vertex_group_normalize);
WM_operatortype_append(OBJECT_OT_vertex_group_normalize_all);
WM_operatortype_append(OBJECT_OT_vertex_group_lock);
WM_operatortype_append(OBJECT_OT_vertex_group_fix);
WM_operatortype_append(OBJECT_OT_vertex_group_invert);
WM_operatortype_append(OBJECT_OT_vertex_group_levels);
WM_operatortype_append(OBJECT_OT_vertex_group_smooth);

View File

@ -1219,363 +1219,6 @@ static bool vgroup_normalize(Object *ob)
return false;
}
/* This finds all of the vertices face-connected to vert by an edge and returns a
* MEM_allocated array of indices of size count.
* count is an int passed by reference so it can be assigned the value of the length here. */
static blender::Vector<int> getSurroundingVerts(Mesh *me, int vert)
{
const MPoly *poly = me->polys().data();
const MLoop *loops = me->loops().data();
int i = me->totpoly;
blender::Vector<int> verts;
while (i--) {
int j = poly->totloop;
int first_l = poly->totloop - 1;
const MLoop *ml = &loops[poly->loopstart];
while (j--) {
/* XXX This assume a vert can only be once in a poly, even though
* it seems logical to me, not totally sure of that. */
if (ml->v == vert) {
int a, b, k;
if (j == first_l) {
/* We are on the first corner. */
a = ml[1].v;
b = ml[j].v;
}
else if (!j) {
/* We are on the last corner. */
a = (ml - 1)->v;
b = loops[poly->loopstart].v;
}
else {
a = (ml - 1)->v;
b = (ml + 1)->v;
}
/* Append a and b verts to array, if not yet present. */
k = verts.size();
/* XXX Maybe a == b is enough? */
while (k-- && !(a == b && a == -1)) {
if (verts[k] == a) {
a = -1;
}
else if (verts[k] == b) {
b = -1;
}
}
if (a != -1) {
verts.append(a);
}
if (b != -1) {
verts.append(b);
}
/* Vert found in this poly, we can go to next one! */
break;
}
ml++;
}
poly++;
}
return verts;
}
/* Get a single point in space by averaging a point cloud (vectors of size 3)
* coord is the place the average is stored,
* points is the point cloud, count is the number of points in the cloud.
*/
static void getSingleCoordinate(float3 *points, int count, float coord[3])
{
int i;
zero_v3(coord);
for (i = 0; i < count; i++) {
add_v3_v3(coord, points[i]);
}
mul_v3_fl(coord, 1.0f / count);
}
/* given a plane and a start and end position,
* compute the amount of vertical distance relative to the plane and store it in dists,
* then get the horizontal and vertical change and store them in changes
*/
static void getVerticalAndHorizontalChange(const float norm[3],
float d,
const float coord[3],
const float start[3],
float distToStart,
float *end,
float (*changes)[2],
float *dists,
int index)
{
/* A = Q - ((Q - P).N)N
* D = (a * x0 + b * y0 +c * z0 + d) */
float projA[3], projB[3];
float plane[4];
plane_from_point_normal_v3(plane, coord, norm);
closest_to_plane_normalized_v3(projA, plane, start);
closest_to_plane_normalized_v3(projB, plane, end);
/* (vertical and horizontal refer to the plane's y and xz respectively)
* vertical distance */
dists[index] = dot_v3v3(norm, end) + d;
/* vertical change */
changes[index][0] = dists[index] - distToStart;
// printf("vc %f %f\n", distance(end, projB, 3) - distance(start, projA, 3), changes[index][0]);
/* horizontal change */
changes[index][1] = len_v3v3(projA, projB);
}
/**
* By changing nonzero weights, try to move a vertex in `me->mverts` with index 'index' to
* `distToBe` distance away from the provided plane strength can change `distToBe` so that it moves
* towards `distToBe` by that percentage `cp` changes how much the weights are adjusted
* to check the distance
*
* `index` is the index of the vertex being moved.
* `norm` and `d` are the plane's properties for the equation: `ax + by + cz + d = 0`.
* `coord` is a point on the plane.
*/
static void moveCloserToDistanceFromPlane(Depsgraph *depsgraph,
Scene * /*scene*/,
Object *ob,
Mesh *me,
int index,
const float norm[3],
const float coord[3],
float d,
float distToBe,
float strength,
float cp)
{
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
Mesh *mesh_eval = (Mesh *)object_eval->data;
Mesh *me_deform;
MDeformWeight *dw, *dw_eval;
float3 m;
MDeformVert *dvert = me->deform_verts_for_write().data() + index;
MDeformVert *dvert_eval = mesh_eval->deform_verts_for_write().data() + index;
int totweight = dvert->totweight;
float oldw = 0;
float oldPos[3] = {0};
float vc, hc, dist = 0.0f;
int i, k;
float(*changes)[2] = static_cast<float(*)[2]>(
MEM_mallocN(sizeof(float[2]) * totweight, "vertHorzChange"));
float *dists = static_cast<float *>(MEM_mallocN(sizeof(float) * totweight, "distance"));
/* track if up or down moved it closer for each bone */
bool *upDown = static_cast<bool *>(MEM_callocN(sizeof(bool) * totweight, "upDownTracker"));
int *dwIndices = static_cast<int *>(MEM_callocN(sizeof(int) * totweight, "dwIndexTracker"));
float distToStart;
int bestIndex = 0;
bool wasChange;
bool wasUp;
int lastIndex = -1;
float originalDistToBe = distToBe;
do {
wasChange = false;
me_deform = mesh_get_eval_deform(depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH);
const Span<float3> positions = me_deform->vert_positions();
m = positions[index];
copy_v3_v3(oldPos, m);
distToStart = dot_v3v3(norm, oldPos) + d;
if (distToBe == originalDistToBe) {
distToBe += distToStart - distToStart * strength;
}
for (i = 0; i < totweight; i++) {
dwIndices[i] = i;
dw = (dvert->dw + i);
dw_eval = (dvert_eval->dw + i);
vc = hc = 0;
if (!dw->weight) {
changes[i][0] = 0;
changes[i][1] = 0;
dists[i] = distToStart;
continue;
}
for (k = 0; k < 2; k++) {
if (me_deform) {
/* DO NOT try to do own cleanup here, this is call for dramatic failures and bugs!
* Better to over-free and recompute a bit. */
BKE_object_free_derived_caches(object_eval);
}
oldw = dw->weight;
if (k) {
dw->weight *= 1 + cp;
}
else {
dw->weight /= 1 + cp;
}
if (dw->weight == oldw) {
changes[i][0] = 0;
changes[i][1] = 0;
dists[i] = distToStart;
break;
}
if (dw->weight > 1) {
dw->weight = 1;
}
dw_eval->weight = dw->weight;
me_deform = mesh_get_eval_deform(depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH);
m = positions[index];
getVerticalAndHorizontalChange(norm, d, coord, oldPos, distToStart, m, changes, dists, i);
dw->weight = oldw;
dw_eval->weight = oldw;
if (!k) {
vc = changes[i][0];
hc = changes[i][1];
dist = dists[i];
}
else {
if (fabsf(dist - distToBe) < fabsf(dists[i] - distToBe)) {
upDown[i] = false;
changes[i][0] = vc;
changes[i][1] = hc;
dists[i] = dist;
}
else {
upDown[i] = true;
}
if (fabsf(dists[i] - distToBe) > fabsf(distToStart - distToBe)) {
changes[i][0] = 0;
changes[i][1] = 0;
dists[i] = distToStart;
}
}
}
}
/* sort the changes by the vertical change */
for (k = 0; k < totweight; k++) {
bestIndex = k;
for (i = k + 1; i < totweight; i++) {
dist = dists[i];
if (fabsf(dist) > fabsf(dists[i])) {
bestIndex = i;
}
}
/* switch with k */
if (bestIndex != k) {
std::swap(upDown[k], upDown[bestIndex]);
std::swap(dwIndices[k], dwIndices[bestIndex]);
swap_v2_v2(changes[k], changes[bestIndex]);
std::swap(dists[k], dists[bestIndex]);
}
}
bestIndex = -1;
/* find the best change with an acceptable horizontal change */
for (i = 0; i < totweight; i++) {
if (fabsf(changes[i][0]) > fabsf(changes[i][1] * 2.0f)) {
bestIndex = i;
break;
}
}
if (bestIndex != -1) {
wasChange = true;
/* it is a good place to stop if it tries to move the opposite direction
* (relative to the plane) of last time */
if (lastIndex != -1) {
if (wasUp != upDown[bestIndex]) {
wasChange = false;
}
}
lastIndex = bestIndex;
wasUp = upDown[bestIndex];
dw = (dvert->dw + dwIndices[bestIndex]);
oldw = dw->weight;
if (upDown[bestIndex]) {
dw->weight *= 1 + cp;
}
else {
dw->weight /= 1 + cp;
}
if (dw->weight > 1) {
dw->weight = 1;
}
if (oldw == dw->weight) {
wasChange = false;
}
if (me_deform) {
/* DO NOT try to do own cleanup here, this is call for dramatic failures and bugs!
* Better to over-free and recompute a bit. */
BKE_object_free_derived_caches(object_eval);
}
}
} while (wasChange && ((distToStart - distToBe) / fabsf(distToStart - distToBe) ==
(dists[bestIndex] - distToBe) / fabsf(dists[bestIndex] - distToBe)));
MEM_freeN(upDown);
MEM_freeN(changes);
MEM_freeN(dists);
MEM_freeN(dwIndices);
}
/* this is used to try to smooth a surface by only adjusting the nonzero weights of a vertex
* but it could be used to raise or lower an existing 'bump.' */
static void vgroup_fix(
const bContext *C, Scene * /*scene*/, Object *ob, float distToBe, float strength, float cp)
{
using namespace blender;
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
Object *object_eval = DEG_get_evaluated_object(depsgraph, ob);
int i;
Mesh *me = static_cast<Mesh *>(ob->data);
if (!(me->editflag & ME_EDIT_PAINT_VERT_SEL)) {
return;
}
const bke::AttributeAccessor attributes = me->attributes();
const VArray<bool> select_vert = attributes.lookup_or_default<bool>(
".select_vert", ATTR_DOMAIN_POINT, false);
for (i = 0; i < me->totvert; i++) {
if (select_vert[i]) {
blender::Vector<int> verts = getSurroundingVerts(me, i);
const int count = verts.size();
if (!verts.is_empty()) {
float3 m;
float3 *p = static_cast<float3 *>(MEM_callocN(sizeof(float3) * (count), "deformedPoints"));
int k;
Mesh *me_deform = mesh_get_eval_deform(
depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH);
const Span<float3> positions_deform = me_deform->vert_positions();
k = count;
while (k--) {
p[k] = positions_deform[verts[k]];
}
if (count >= 3) {
float d /*, dist */ /* UNUSED */, mag;
float coord[3];
float norm[3];
getSingleCoordinate(p, count, coord);
m = positions_deform[i];
sub_v3_v3v3(norm, m, coord);
mag = normalize_v3(norm);
if (mag) { /* zeros fix */
d = -dot_v3v3(norm, coord);
// dist = (dot_v3v3(norm, m.co) + d); /* UNUSED */
moveCloserToDistanceFromPlane(
depsgraph, scene_eval, object_eval, me, i, norm, coord, d, distToBe, strength, cp);
}
}
MEM_freeN(p);
}
}
}
}
static void vgroup_levels_subset(Object *ob,
const bool *vgroup_validmap,
const int vgroup_tot,
@ -2732,36 +2375,6 @@ static bool vertex_group_poll(bContext *C)
return vertex_group_poll_ex(C, ob);
}
static bool vertex_group_mesh_poll_ex(bContext *C, Object *ob)
{
if (!vertex_group_poll_ex(C, ob)) {
return false;
}
if (ob->type != OB_MESH) {
CTX_wm_operator_poll_msg_set(C, "Only mesh objects are supported");
return false;
}
return true;
}
static bool vertex_group_mesh_with_dvert_poll(bContext *C)
{
Object *ob = ED_object_context(C);
if (!vertex_group_mesh_poll_ex(C, ob)) {
return false;
}
Mesh *me = static_cast<Mesh *>(ob->data);
if (me->deform_verts().is_empty()) {
CTX_wm_operator_poll_msg_set(C, "The active mesh object has no vertex group data");
return false;
}
return true;
}
static bool UNUSED_FUNCTION(vertex_group_poll_edit)(bContext *C)
{
Object *ob = ED_object_context(C);
@ -3338,89 +2951,6 @@ void OBJECT_OT_vertex_group_normalize_all(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Vertex Group Fix Position Operator
* \{ */
static int vertex_group_fix_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
Scene *scene = CTX_data_scene(C);
float distToBe = RNA_float_get(op->ptr, "dist");
float strength = RNA_float_get(op->ptr, "strength");
float cp = RNA_float_get(op->ptr, "accuracy");
ModifierData *md = static_cast<ModifierData *>(ob->modifiers.first);
while (md) {
if (md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime)) {
break;
}
md = md->next;
}
if (md && md->type == eModifierType_Mirror) {
BKE_report(op->reports,
RPT_ERROR_INVALID_CONTEXT,
"This operator does not support an active mirror modifier");
return OPERATOR_CANCELLED;
}
vgroup_fix(C, scene, ob, distToBe, strength, cp);
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob);
WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data);
return OPERATOR_FINISHED;
}
void OBJECT_OT_vertex_group_fix(wmOperatorType *ot)
{
/* identifiers */
ot->name = "Fix Vertex Group Deform";
ot->idname = "OBJECT_OT_vertex_group_fix";
ot->description =
"Modify the position of selected vertices by changing only their respective "
"groups' weights (this tool may be slow for many vertices)";
/* api callbacks */
ot->poll = vertex_group_mesh_with_dvert_poll;
ot->exec = vertex_group_fix_exec;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_float(ot->srna,
"dist",
0.0f,
-FLT_MAX,
FLT_MAX,
"Distance",
"The distance to move to",
-10.0f,
10.0f);
RNA_def_float(ot->srna,
"strength",
1.0f,
-2.0f,
FLT_MAX,
"Strength",
"The distance moved can be changed by this multiplier",
-2.0f,
2.0f);
RNA_def_float(
ot->srna,
"accuracy",
1.0f,
0.05f,
FLT_MAX,
"Change Sensitivity",
"Change the amount weights are altered with each iteration: lower values are slower",
0.05f,
1.0f);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Vertex Group Lock Operator
* \{ */