Fix T67934: Weight paint doesn't work with Subsurf/Multires

This is a regression since PBVH was introduced for weight paint.

The solution is: treat subsurf and multires modifiers as deforming
ones for the weight painting. This is an easiest solution to make
PBVH use subdivided location of original vertices.

This change could simplify some of the weight paint by removing
the grids check, since PBVH is not supposed to be built from grids
in this case anymore.

Differential Revision: https://developer.blender.org/D5751
This commit is contained in:
Sergey Sharybin 2019-09-11 11:14:06 +02:00
parent 74d27bb0ef
commit 5e332fd700
Notes: blender-bot 2023-02-14 06:11:15 +01:00
Referenced by commit f1ac64921b, Fix T71213: Mask or Mirror before Armature breaks weight paint.
Referenced by issue #88665, Impossible to weight paint certain vertices
Referenced by issue #70476, Pose brush breaks with subdiv modifier
Referenced by issue #67934, Subdivision modifier and multirres modifier broke for weight paint, vertex paint and sculpt
Referenced by issue #54082, Subsurf modifier is affecting the way in which the brush paints weights.
2 changed files with 65 additions and 25 deletions

View File

@ -342,6 +342,28 @@ static void crazyspace_init_object_for_eval(struct Depsgraph *depsgraph,
}
}
static void crazyspace_init_verts_and_matrices(const Mesh *mesh,
float (**deformmats)[3][3],
float (**deformcos)[3])
{
int num_verts;
*deformcos = BKE_mesh_vert_coords_alloc(mesh, &num_verts);
*deformmats = MEM_callocN(sizeof(**deformmats) * num_verts, "defmats");
for (int a = 0; a < num_verts; a++) {
unit_m3((*deformmats)[a]);
}
BLI_assert(num_verts == mesh->totvert);
}
static bool crazyspace_modifier_supports_deform(ModifierData *md)
{
if (ELEM(md->type, eModifierType_Subsurf, eModifierType_Multires)) {
return true;
}
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
return (mti->type == eModifierTypeType_OnlyDeform);
}
int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
Scene *scene,
Object *object,
@ -349,25 +371,23 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
float (**deformcos)[3])
{
ModifierData *md;
Mesh *me_eval;
int a, numVerts = 0;
Mesh *me_eval = NULL;
float(*defmats)[3][3] = NULL, (*deformedVerts)[3] = NULL;
int numleft = 0;
VirtualModifierData virtualModifierData;
Object object_eval;
crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
MultiresModifierData *mmd = get_multires_modifier(scene, &object_eval, 0);
const bool is_sculpt_mode = (object->mode & OB_MODE_SCULPT) != 0;
const bool has_multires = mmd != NULL && mmd->sculptlvl > 0;
const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
if (has_multires) {
if (is_sculpt_mode && has_multires) {
*deformmats = NULL;
*deformcos = NULL;
return numleft;
}
me_eval = NULL;
md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
for (; md; md = md->next) {
@ -378,41 +398,37 @@ int BKE_sculpt_get_first_deform_matrices(struct Depsgraph *depsgraph,
}
if (mti->type == eModifierTypeType_OnlyDeform) {
if (!defmats) {
if (defmats == NULL) {
/* NOTE: Evaluated object si re-set to its original undeformed
* state. */
Mesh *me = object_eval.data;
me_eval = BKE_mesh_copy_for_eval(me, true);
deformedVerts = BKE_mesh_vert_coords_alloc(me, &numVerts);
defmats = MEM_callocN(sizeof(*defmats) * numVerts, "defmats");
for (a = 0; a < numVerts; a++) {
unit_m3(defmats[a]);
}
crazyspace_init_verts_and_matrices(me_eval, &defmats, &deformedVerts);
}
if (mti->deformMatrices) {
mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, numVerts);
mti->deformMatrices(md, &mectx, me_eval, deformedVerts, defmats, me_eval->totvert);
}
else {
break;
}
}
else {
break;
}
}
for (; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
continue;
}
if (mti->type == eModifierTypeType_OnlyDeform) {
if (crazyspace_modifier_supports_deform(md)) {
numleft++;
}
}
if (me_eval) {
if (me_eval != NULL) {
BKE_id_free(NULL, me_eval);
}
@ -435,6 +451,13 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
/* there are deformation modifier which doesn't support deformation matrices
* calculation. Need additional crazyspace correction */
Mesh *mesh = (Mesh *)object->data;
Mesh *mesh_eval = NULL;
if (*deformcos == NULL) {
crazyspace_init_verts_and_matrices(mesh, deformmats, deformcos);
}
float(*deformedVerts)[3] = *deformcos;
float(*origVerts)[3] = MEM_dupallocN(deformedVerts);
float(*quats)[4];
@ -444,23 +467,26 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
crazyspace_init_object_for_eval(depsgraph, object, &object_eval);
ModifierData *md = modifiers_getVirtualModifierList(&object_eval, &virtualModifierData);
const ModifierEvalContext mectx = {depsgraph, &object_eval, 0};
Mesh *mesh = (Mesh *)object->data;
for (; md; md = md->next) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
continue;
}
if (mti->type == eModifierTypeType_OnlyDeform) {
if (crazyspace_modifier_supports_deform(md)) {
const ModifierTypeInfo *mti = modifierType_getInfo(md->type);
/* skip leading modifiers which have been already
* handled in sculpt_get_first_deform_matrices */
if (mti->deformMatrices && !deformed) {
continue;
}
mti->deformVerts(md, &mectx, NULL, deformedVerts, mesh->totvert);
if (mesh_eval == NULL) {
mesh_eval = BKE_mesh_copy_for_eval(mesh, true);
}
mti->deformVerts(md, &mectx, mesh_eval, deformedVerts, mesh_eval->totvert);
deformed = 1;
}
}
@ -479,6 +505,10 @@ void BKE_crazyspace_build_sculpt(struct Depsgraph *depsgraph,
MEM_freeN(origVerts);
MEM_freeN(quats);
if (mesh_eval != NULL) {
BKE_id_free(NULL, mesh_eval);
}
}
if (*deformmats == NULL) {

View File

@ -1104,6 +1104,12 @@ MultiresModifierData *BKE_sculpt_multires_active(Scene *scene, Object *ob)
return NULL;
}
/* Weight paint operates on original vertices, and needs to treat multires as regular modifier
* to make it so that PBVH vertices are at the multires surface. */
if ((ob->mode & OB_MODE_SCULPT) == 0) {
return NULL;
}
for (md = modifiers_getVirtualModifierList(ob, &virtualModifierData); md; md = md->next) {
if (md->type == eModifierType_Multires) {
MultiresModifierData *mmd = (MultiresModifierData *)md;
@ -1149,7 +1155,10 @@ static bool sculpt_modifiers_active(Scene *scene, Sculpt *sd, Object *ob)
if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
continue;
}
if (ELEM(md->type, eModifierType_ShapeKey, eModifierType_Multires)) {
if (md->type == eModifierType_Multires && (ob->mode & OB_MODE_SCULPT)) {
continue;
}
if (md->type == eModifierType_ShapeKey) {
continue;
}
@ -1199,8 +1208,9 @@ static void sculpt_update_object(
ss->kb = (mmd == NULL) ? BKE_keyblock_from_object(ob) : NULL;
/* VWPaint require mesh info for loop lookup, so require sculpt mode here */
if (mmd && ob->mode & OB_MODE_SCULPT) {
/* NOTE: Weight pPaint require mesh info for loop lookup, but it never uses multires code path,
* so no extra checks is needed here. */
if (mmd) {
ss->multires = mmd;
ss->totvert = me_eval->totvert;
ss->totpoly = me_eval->totpoly;