|
|
|
@ -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
|
|
|
|
|
* \{ */
|
|
|
|
|