Fix T44611: 'make_links_data' modifiers would fail and crash with multires modifier.
Since it was not ensuring dest has valid mdisp data matching new multires modifier subdiv level... Also, fixed a bug in `multires_subdivide()`, which would crash when trying to increase from level 0 (aka no subdiv) to > 1 (wrong check, trying to interpolate when it should not). And added a few sanity checks.
This commit is contained in:
@@ -79,8 +79,9 @@ struct DerivedMesh *get_multires_dm(struct Scene *scene, struct MultiresModifier
|
||||
struct Object *ob);
|
||||
void multiresModifier_del_levels(struct MultiresModifierData *, struct Object *, int direction);
|
||||
void multiresModifier_base_apply(struct MultiresModifierData *mmd, struct Object *ob);
|
||||
void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object *ob,
|
||||
int updateblock, int simple);
|
||||
void multiresModifier_subdivide(struct MultiresModifierData *mmd, struct Object *ob, int updateblock, int simple);
|
||||
void multiresModifier_sync_levels_ex(
|
||||
struct Object *ob_dst, struct MultiresModifierData *mmd_src, struct MultiresModifierData *mmd_dst);
|
||||
int multiresModifier_reshape(struct Scene *scene, struct MultiresModifierData *mmd,
|
||||
struct Object *dst, struct Object *src);
|
||||
int multiresModifier_reshapeFromDM(struct Scene *scene, struct MultiresModifierData *mmd,
|
||||
|
||||
@@ -882,18 +882,20 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
|
||||
{
|
||||
Mesh *me = ob->data;
|
||||
MDisps *mdisps;
|
||||
int lvl = mmd->totlvl;
|
||||
const int lvl = mmd->totlvl;
|
||||
|
||||
if ((totlvl > multires_max_levels) || (me->totpoly == 0))
|
||||
return;
|
||||
|
||||
BLI_assert(totlvl > lvl);
|
||||
|
||||
multires_force_update(ob);
|
||||
|
||||
mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
|
||||
if (!mdisps)
|
||||
mdisps = multires_mdisps_initialize_hidden(me, totlvl);
|
||||
|
||||
if (mdisps->disps && !updateblock && totlvl > 1) {
|
||||
if (mdisps->disps && !updateblock && lvl != 0) {
|
||||
/* upsample */
|
||||
DerivedMesh *lowdm, *cddm, *highdm;
|
||||
CCGElem **highGridData, **lowGridData, **subGridData;
|
||||
@@ -910,6 +912,7 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl
|
||||
|
||||
/* create multires DM from original mesh at low level */
|
||||
lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple, has_mask);
|
||||
BLI_assert(lowdm != cddm);
|
||||
cddm->release(cddm);
|
||||
|
||||
/* copy subsurf grids and replace them with low displaced grids */
|
||||
@@ -2137,27 +2140,38 @@ void multires_load_old(Object *ob, Mesh *me)
|
||||
me->mr = NULL;
|
||||
}
|
||||
|
||||
/* If 'ob' and 'to_ob' both have multires modifiers, synchronize them
|
||||
* such that 'ob' has the same total number of levels as 'to_ob'. */
|
||||
static void multires_sync_levels(Scene *scene, Object *ob, Object *to_ob)
|
||||
/* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them
|
||||
* such that 'ob_dst' has the same total number of levels as 'ob_src'. */
|
||||
void multiresModifier_sync_levels_ex(Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst)
|
||||
{
|
||||
MultiresModifierData *mmd = get_multires_modifier(scene, ob, 1);
|
||||
MultiresModifierData *to_mmd = get_multires_modifier(scene, to_ob, 1);
|
||||
if (mmd_src->totlvl == mmd_dst->totlvl) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mmd) {
|
||||
if (mmd_src->totlvl > mmd_dst->totlvl) {
|
||||
multires_subdivide(mmd_dst, ob_dst, mmd_src->totlvl, false, mmd_dst->simple);
|
||||
}
|
||||
else {
|
||||
multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl);
|
||||
}
|
||||
}
|
||||
|
||||
static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst)
|
||||
{
|
||||
MultiresModifierData *mmd_src = get_multires_modifier(scene, ob_src, true);
|
||||
MultiresModifierData *mmd_dst = get_multires_modifier(scene, ob_dst, true);
|
||||
|
||||
if (!mmd_src) {
|
||||
/* object could have MDISP even when there is no multires modifier
|
||||
* this could lead to troubles due to i've got no idea how mdisp could be
|
||||
* upsampled correct without modifier data.
|
||||
* just remove mdisps if no multires present (nazgul) */
|
||||
|
||||
multires_customdata_delete(ob->data);
|
||||
multires_customdata_delete(ob_src->data);
|
||||
}
|
||||
|
||||
if (mmd && to_mmd) {
|
||||
if (mmd->totlvl > to_mmd->totlvl)
|
||||
multires_del_higher(mmd, ob, to_mmd->totlvl);
|
||||
else
|
||||
multires_subdivide(mmd, ob, to_mmd->totlvl, 0, mmd->simple);
|
||||
if (mmd_src && mmd_dst) {
|
||||
multiresModifier_sync_levels_ex(ob_dst, mmd_src, mmd_dst);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2276,7 +2290,7 @@ void multiresModifier_scale_disp(Scene *scene, Object *ob)
|
||||
void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob)
|
||||
{
|
||||
float smat[3][3], tmat[3][3], mat[3][3];
|
||||
multires_sync_levels(scene, ob, to_ob);
|
||||
multires_sync_levels(scene, to_ob, ob);
|
||||
|
||||
/* construct scale matrix for displacement */
|
||||
BKE_object_scale_to_mat3(to_ob, tmat);
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
#include "BKE_editmesh.h"
|
||||
#include "BKE_mball.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_multires.h"
|
||||
#include "BKE_node.h"
|
||||
#include "BKE_object.h"
|
||||
#include "BKE_paint.h"
|
||||
@@ -280,6 +281,12 @@ void BKE_object_link_modifiers(struct Object *ob_dst, struct Object *ob_src)
|
||||
|
||||
nmd = modifier_new(md->type);
|
||||
BLI_strncpy(nmd->name, md->name, sizeof(nmd->name));
|
||||
|
||||
if (md->type == eModifierType_Multires) {
|
||||
/* Has to be done after mod creation, but *before* we actually copy its settings! */
|
||||
multiresModifier_sync_levels_ex(ob_dst, (MultiresModifierData *)md, (MultiresModifierData *)nmd);
|
||||
}
|
||||
|
||||
modifier_copyData(md, nmd);
|
||||
BLI_addtail(&ob_dst->modifiers, nmd);
|
||||
modifier_unique_name(&ob_dst->modifiers, nmd);
|
||||
|
||||
Reference in New Issue
Block a user