Armature: Switch envelope weight calculation to the new subdiv code

There should be minimal user-measurable changes since the old algorithm
is not the same as OpenSubdiv. For example now creases (both edge and
vertex ones) are properly supported.

This allows to have less dependencies on the old subdivision surface code
which ideally will be removed soon.

Pull Request: https://projects.blender.org/blender/blender/pulls/143712
This commit is contained in:
Sergey Sharybin
2025-08-08 16:29:12 +02:00
committed by Sergey Sharybin
parent d6cc9a0793
commit 55942f5fbe
3 changed files with 57 additions and 9 deletions

View File

@@ -45,4 +45,11 @@ float3 mesh_interpolate_position_on_edge(Span<float3> coarse_positions,
bool is_simple,
float u);
/**
* Calculate positions position of the given mesh vertices at the limit surface of the mesh.
*
* The limit_positions is to be sized at exactly the number of the base mesh vertices.
*/
void calculate_limit_positions(Mesh *mesh, MutableSpan<float3> limit_positions);
} // namespace blender::bke::subdiv

View File

@@ -20,6 +20,7 @@
#include "BKE_mesh.hh"
#include "BKE_mesh_mapping.hh"
#include "BKE_subdiv.hh"
#include "BKE_subdiv_deform.hh"
#include "BKE_subdiv_eval.hh"
#include "BKE_subdiv_foreach.hh"
#include "BKE_subdiv_mesh.hh"
@@ -1246,4 +1247,35 @@ Mesh *subdiv_to_mesh(Subdiv *subdiv, const ToMeshSettings *settings, const Mesh
/** \} */
/* -------------------------------------------------------------------- */
/** \name Limit surface
* \{ */
void calculate_limit_positions(Mesh *mesh, MutableSpan<float3> limit_positions)
{
BLI_assert(mesh->verts_num == limit_positions.size());
limit_positions.copy_from(mesh->vert_positions());
Settings settings{};
settings.is_simple = false;
settings.is_adaptive = true;
settings.level = 1;
settings.use_creases = true;
/* Default subdivision surface modifier settings:
* - UV Smooth:Keep Corners.
* - BoundarySmooth: All. */
settings.vtx_boundary_interpolation = SUBDIV_VTX_BOUNDARY_EDGE_ONLY;
settings.fvar_linear_interpolation = SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS;
Subdiv *subdiv = update_from_mesh(nullptr, &settings, mesh);
if (subdiv) {
deform_coarse_vertices(subdiv, mesh, limit_positions);
free(subdiv);
}
}
/** \} */
} // namespace blender::bke::subdiv

View File

@@ -27,6 +27,7 @@
#include "BKE_object.hh"
#include "BKE_object_deform.h"
#include "BKE_report.hh"
#include "BKE_subdiv_mesh.hh"
#include "BKE_subsurf.hh"
#include "DEG_depsgraph.hh"
@@ -199,7 +200,7 @@ static int dgroup_skinnable_cb(Object *ob, Bone *bone, void *datap)
static void envelope_bone_weighting(Object *ob,
Mesh *mesh,
float (*verts)[3],
const blender::Span<blender::float3> verts,
int numbones,
Bone **bonelist,
bDeformGroup **dgrouplist,
@@ -298,7 +299,8 @@ static void add_verts_to_dgroups(ReportList *reports,
bPoseChannel *pchan;
Mesh *mesh;
Mat4 bbone_array[MAX_BBONE_SUBDIV], *bbone = nullptr;
float(*root)[3], (*tip)[3], (*verts)[3];
float(*root)[3], (*tip)[3];
blender::Array<blender::float3> verts;
bool *selected;
int numbones, vertsfilled = 0, segments = 0;
const bool wpmode = (ob->mode & OB_MODE_WEIGHT_PAINT);
@@ -412,15 +414,15 @@ static void add_verts_to_dgroups(ReportList *reports,
/* create verts */
mesh = static_cast<Mesh *>(ob->data);
verts = static_cast<float(*)[3]>(
MEM_callocN(mesh->verts_num * sizeof(*verts), "closestboneverts"));
verts.reinitialize(mesh->verts_num);
if (wpmode) {
/* if in weight paint mode, use final verts from evaluated mesh */
const Object *ob_eval = DEG_get_evaluated(depsgraph, ob);
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
if (mesh_eval) {
BKE_mesh_foreach_mapped_vert_coords_get(mesh_eval, verts, mesh->verts_num);
BKE_mesh_foreach_mapped_vert_coords_get(
mesh_eval, reinterpret_cast<float(*)[3]>(verts.data()), mesh->verts_num);
vertsfilled = 1;
}
}
@@ -428,7 +430,7 @@ static void add_verts_to_dgroups(ReportList *reports,
/* Is subdivision-surface on? Lets use the verts on the limit surface then.
* = same amount of vertices as mesh, but vertices moved to the
* subdivision-surfaced position, like for 'optimal'. */
subsurf_calculate_limit_positions(mesh, verts);
blender::bke::subdiv::calculate_limit_positions(mesh, verts);
vertsfilled = 1;
}
@@ -445,8 +447,16 @@ static void add_verts_to_dgroups(ReportList *reports,
if (heat) {
const char *error = nullptr;
heat_bone_weighting(
ob, mesh, verts, numbones, dgrouplist, dgroupflip, root, tip, selected, &error);
heat_bone_weighting(ob,
mesh,
reinterpret_cast<float(*)[3]>(verts.data()),
numbones,
dgrouplist,
dgroupflip,
root,
tip,
selected,
&error);
if (error) {
BKE_report(reports, RPT_WARNING, error);
}
@@ -475,7 +485,6 @@ static void add_verts_to_dgroups(ReportList *reports,
MEM_freeN(root);
MEM_freeN(tip);
MEM_freeN(selected);
MEM_freeN(verts);
}
void ED_object_vgroup_calc_from_armature(ReportList *reports,