Shrinkwrap: Use OpenSubdiv instead of legacy DerivedMesh

The title says it pretty much all: the shrinkwrap modifier is no longer
dependent on the legacy DerivedMesh.

The benefits for doing this are:
- The DerivedMesh is closer to be removed from the codebase.
- Only base vertices are subdivided which could result in better
  performance and memory usage.
- Proper crease support (for edges and vertices).

The downside of using OpenSubdiv is that the topology refiner might be
expensive to calculate, so for meshes with a lot of extraordinary faces
(such as n-gons, triangles) the performance will be worse.

Pull Request: https://projects.blender.org/blender/blender/pulls/143706
This commit is contained in:
Sergey Sharybin
2025-08-08 12:44:10 +02:00
committed by Sergey Sharybin
parent 8e9c68f6a3
commit cda9ff445f

View File

@@ -27,14 +27,16 @@
#include "BLI_utildefines.h"
#include "BKE_attribute.hh"
#include "BKE_mesh_legacy_derived_mesh.hh"
#include "BKE_modifier.hh"
#include "BKE_shrinkwrap.hh"
#include "BKE_subdiv.hh"
#include "BKE_deform.hh"
#include "BKE_editmesh.hh"
#include "BKE_mesh.hh" /* for OMP limits. */
#include "BKE_mesh_wrapper.hh"
#include "BKE_subdiv.hh"
#include "BKE_subdiv_deform.hh"
#include "BKE_subsurf.hh"
#include "DEG_depsgraph_query.hh"
@@ -1335,9 +1337,39 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc)
0, calc->numVerts, &data, shrinkwrap_calc_nearest_surface_point_cb_ex, &settings);
}
static blender::Array<blender::float3> shrinkwrap_calc_subdivided_positions(
Mesh *mesh, const int subdivision_level)
{
using namespace blender;
using namespace blender::bke;
Array<float3> positions = mesh->vert_positions();
subdiv::Settings settings{};
settings.is_simple = false;
settings.is_adaptive = false;
settings.level = subdivision_level;
settings.use_creases = true;
/* Default subdivision surface modifier settings:
* - UV Smooth:Keep Corners.
* - BoundarySmooth: All. */
settings.vtx_boundary_interpolation = subdiv::SUBDIV_VTX_BOUNDARY_EDGE_ONLY;
settings.fvar_linear_interpolation =
subdiv::SUBDIV_FVAR_LINEAR_INTERPOLATION_CORNERS_AND_JUNCTIONS;
subdiv::Subdiv *subdiv = subdiv::update_from_mesh(nullptr, &settings, mesh);
if (subdiv) {
subdiv::deform_coarse_vertices(subdiv, mesh, positions);
subdiv::free(subdiv);
}
return positions;
}
void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
const ModifierEvalContext *ctx,
Scene *scene,
Scene * /*scene*/,
Object *ob,
Mesh *mesh,
const MDeformVert *dvert,
@@ -1345,9 +1377,8 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
float (*vertexCos)[3],
int numVerts)
{
DerivedMesh *ss_mesh = nullptr;
ShrinkwrapCalcData calc = NULL_ShrinkwrapCalcData;
blender::Array<blender::float3> subdivided_positions;
/* remove loop dependencies on derived meshes (TODO should this be done elsewhere?) */
if (smd->target == ob) {
@@ -1387,35 +1418,8 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
/* Using vertices positions/normals as if a subsurface was applied */
if (smd->subsurfLevels) {
SubsurfModifierData ssmd = {{nullptr}};
ssmd.subdivType = ME_CC_SUBSURF; /* catmull clark */
ssmd.levels = smd->subsurfLevels; /* levels */
/* TODO: to be moved to Mesh once we are done with changes in subsurf code. */
DerivedMesh *dm = CDDM_from_mesh(mesh);
ss_mesh = subsurf_make_derived_from_derived(
dm,
&ssmd,
scene,
nullptr,
(ob->mode & OB_MODE_EDIT) ? SUBSURF_IN_EDIT_MODE : SubsurfFlags(0));
if (ss_mesh) {
calc.vert_positions = reinterpret_cast<float(*)[3]>(ss_mesh->getVertArray(ss_mesh));
if (calc.vert_positions) {
/* TRICKY: this code assumes subsurface will have the transformed original vertices
* in their original order at the end of the vert array. */
calc.vert_positions = calc.vert_positions + ss_mesh->getNumVerts(ss_mesh) -
dm->getNumVerts(dm);
}
}
/* Just to make sure we are not leaving any memory behind */
BLI_assert(ssmd.emCache == nullptr);
BLI_assert(ssmd.mCache == nullptr);
dm->release(dm);
subdivided_positions = shrinkwrap_calc_subdivided_positions(mesh, smd->subsurfLevels);
calc.vert_positions = reinterpret_cast<float(*)[3]>(subdivided_positions.data());
}
}
@@ -1442,11 +1446,6 @@ void shrinkwrapModifier_deform(ShrinkwrapModifierData *smd,
BKE_shrinkwrap_free_tree(&tree);
}
/* free memory */
if (ss_mesh) {
ss_mesh->release(ss_mesh);
}
}
void shrinkwrapParams_deform(const ShrinkwrapParams &params,