diff options
-rw-r--r-- | source/blender/blenkernel/BKE_multires.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/BKE_subsurf.h | 3 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/CCGSubSurf.c | 18 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/CCGSubSurf.h | 1 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/multires.c | 123 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/subsurf_ccg.c | 22 | ||||
-rw-r--r-- | source/blender/modifiers/intern/MOD_multires.c | 1 |
7 files changed, 144 insertions, 27 deletions
diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index e695fb83c23..396f849def1 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -44,7 +44,7 @@ struct MultiresModifierData; struct Object; struct Scene; -/* Delete mesh mdisps */ +/* Delete mesh mdisps and grid paint masks */ void multires_customdata_delete(struct Mesh *me); void multires_mark_as_modified(struct Object *ob, enum MultiresModifiedFlags flags); @@ -62,6 +62,7 @@ void multiresModifier_set_levels_from_disps(struct MultiresModifierData *mmd, st typedef enum { MULTIRES_USE_LOCAL_MMD = 1, MULTIRES_USE_RENDER_PARAMS = 2, + MULTIRES_ALLOC_PAINT_MASK = 4 } MultiresFlags; struct DerivedMesh *multires_make_derived_from_derived(struct DerivedMesh *dm, diff --git a/source/blender/blenkernel/BKE_subsurf.h b/source/blender/blenkernel/BKE_subsurf.h index c4d23a327d7..60a1e6ab68f 100644 --- a/source/blender/blenkernel/BKE_subsurf.h +++ b/source/blender/blenkernel/BKE_subsurf.h @@ -59,7 +59,8 @@ typedef enum { SUBSURF_USE_RENDER_PARAMS = 1, SUBSURF_IS_FINAL_CALC = 2, SUBSURF_FOR_EDIT_MODE = 4, - SUBSURF_IN_EDIT_MODE = 8 + SUBSURF_IN_EDIT_MODE = 8, + SUBSURF_ALLOC_PAINT_MASK = 16 } SubsurfFlags; struct DerivedMesh *subsurf_make_derived_from_derived( diff --git a/source/blender/blenkernel/intern/CCGSubSurf.c b/source/blender/blenkernel/intern/CCGSubSurf.c index a15d5938641..42c9fa84a91 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.c +++ b/source/blender/blenkernel/intern/CCGSubSurf.c @@ -387,6 +387,10 @@ struct CCGSubSurf { int calcVertNormals; int normalDataOffset; + /* data for paint masks */ + int allocMask; + int maskDataOffset; + /* data for age'ing (to debug sync) */ int currentAge; int useAgeCounts; @@ -852,6 +856,8 @@ CCGSubSurf *ccgSubSurf_new(CCGMeshIFC *ifc, int subdivLevels, CCGAllocatorIFC *a ss->calcVertNormals = 0; ss->normalDataOffset = 0; + ss->allocMask = 0; + ss->q = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize); ss->r = CCGSUBSURF_alloc(ss, ss->meshIFC.vertDataSize); @@ -996,6 +1002,12 @@ CCGError ccgSubSurf_setCalcVertexNormals(CCGSubSurf *ss, int useVertNormals, int return eCCGError_None; } +void ccgSubSurf_setAllocMask(CCGSubSurf *ss, int allocMask, int maskOffset) +{ + ss->allocMask = allocMask; + ss->maskDataOffset = maskOffset; +} + void ccgSubSurf_setNumLayers(CCGSubSurf *ss, int numLayers) { ss->meshIFC.numLayers = numLayers; @@ -3123,6 +3135,12 @@ void CCG_key(CCGKey *key, const CCGSubSurf *ss, int level) key->grid_size = ccgSubSurf_getGridLevelSize(ss, level); key->grid_area = key->grid_size * key->grid_size; key->grid_bytes = key->elem_size * key->grid_area; + + key->has_mask = ss->allocMask; + if (key->has_mask) + key->mask_offset = ss->maskDataOffset; + else + key->mask_offset = -1; } void CCG_key_top_level(CCGKey *key, const CCGSubSurf *ss) diff --git a/source/blender/blenkernel/intern/CCGSubSurf.h b/source/blender/blenkernel/intern/CCGSubSurf.h index 76e1911b0a5..33b37ac281c 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf.h +++ b/source/blender/blenkernel/intern/CCGSubSurf.h @@ -76,6 +76,7 @@ void ccgSubSurf_getUseAgeCounts (CCGSubSurf *ss, int *useAgeCounts_r, int *ve CCGError ccgSubSurf_setUseAgeCounts (CCGSubSurf *ss, int useAgeCounts, int vertUserOffset, int edgeUserOffset, int faceUserOffset); CCGError ccgSubSurf_setCalcVertexNormals (CCGSubSurf *ss, int useVertNormals, int normalDataOffset); +void ccgSubSurf_setAllocMask (CCGSubSurf *ss, int allocMask, int maskOffset); void ccgSubSurf_setNumLayers (CCGSubSurf *ss, int numLayers); diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 73705ab3752..bd23e92fe9e 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -90,12 +90,17 @@ void multires_customdata_delete(Mesh *me) CustomData_external_remove(&em->bm->ldata, &me->id, CD_MDISPS, 0); BM_data_layer_free(em->bm, &em->bm->ldata, CD_MDISPS); + + BM_data_layer_free(em->bm, &em->bm->ldata, CD_GRID_PAINT_MASK); } else { CustomData_external_remove(&me->ldata, &me->id, CD_MDISPS, me->totloop); CustomData_free_layer_active(&me->ldata, CD_MDISPS, - me->totloop); + me->totloop); + + CustomData_free_layer_active(&me->ldata, CD_GRID_PAINT_MASK, + me->totloop); } } @@ -594,15 +599,40 @@ static void multires_copy_dm_grid(CCGElem *gridA, CCGElem *gridB, CCGKey *keyA, } } +/* Reallocate gpm->data at a lower resolution and copy values over + from the original high-resolution data */ +static void multires_grid_paint_mask_downsample(GridPaintMask *gpm, int level) +{ + if (level < gpm->level) { + int gridsize = ccg_gridsize(level); + float *data = MEM_callocN(sizeof(float) * gridsize * gridsize, + "multires_grid_paint_mask_downsample"); + int x, y; + + for (y = 0; y < gridsize; y++) { + for (x = 0; x < gridsize; x++) { + data[y * gridsize + x] = + paint_grid_paint_mask(gpm, level, x, y); + } + } + + MEM_freeN(gpm->data); + gpm->data = data; + gpm->level = level; + } +} + static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl) { Mesh *me = (Mesh *)ob->data; int levels = mmd->totlvl - lvl; MDisps *mdisps; + GridPaintMask *gpm; multires_set_tot_mdisps(me, mmd->totlvl); CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); + gpm = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK); multires_force_update(ob); @@ -615,7 +645,8 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl) for (i = 0; i < me->totpoly; ++i) { for (j = 0; j < me->mpoly[i].totloop; j++) { - MDisps *mdisp = &mdisps[me->mpoly[i].loopstart + j]; + int g = me->mpoly[i].loopstart + j; + MDisps *mdisp = &mdisps[g]; float (*disps)[3], (*ndisps)[3], (*hdisps)[3]; int totdisp = multires_grid_tot[lvl]; @@ -641,6 +672,8 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl) mdisp->disps = disps; mdisp->totdisp = totdisp; mdisp->level = lvl; + + multires_grid_paint_mask_downsample(&gpm[g], lvl); } } } @@ -673,9 +706,10 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int dire multires_set_tot_level(ob, mmd, lvl); } -static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int totlvl, int simple) +static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int totlvl, int simple, int alloc_paint_mask) { MultiresModifierData mmd = {{NULL}}; + MultiresFlags flags = MULTIRES_USE_LOCAL_MMD; mmd.lvl = lvl; mmd.sculptlvl = lvl; @@ -683,10 +717,13 @@ static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lv mmd.totlvl = totlvl; mmd.simple = simple; - return multires_make_derived_from_derived(dm, &mmd, ob, MULTIRES_USE_LOCAL_MMD); + if (alloc_paint_mask) + flags |= MULTIRES_ALLOC_PAINT_MASK; + + return multires_make_derived_from_derived(dm, &mmd, ob, flags); } -static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int simple, int optimal, int plain_uv) +static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int simple, int optimal, int plain_uv, int alloc_paint_mask) { SubsurfModifierData smd = {{NULL}}; SubsurfFlags flags = 0; @@ -701,6 +738,10 @@ static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl if (ob->mode & OB_MODE_EDIT) flags |= SUBSURF_IN_EDIT_MODE; + + if (alloc_paint_mask) + flags |= SUBSURF_ALLOC_PAINT_MASK; + return subsurf_make_derived_from_derived(dm, &smd, NULL, flags); } @@ -737,7 +778,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob) /* generate highest level with displacements */ cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - dispdm = multires_dm_create_local(ob, cddm, totlvl, totlvl, 0); + dispdm = multires_dm_create_local(ob, cddm, totlvl, totlvl, 0, 0); cddm->release(cddm); /* copy the new locations of the base verts into the mesh */ @@ -827,7 +868,7 @@ void multiresModifier_base_apply(MultiresModifierData *mmd, Object *ob) /* subdivide the mesh to highest level without displacements */ cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - origdm = subsurf_dm_create_local(ob, cddm, totlvl, 0, 0, mmd->flags & eMultiresModifierFlag_PlainUv); + origdm = subsurf_dm_create_local(ob, cddm, totlvl, 0, 0, mmd->flags & eMultiresModifierFlag_PlainUv, 0); cddm->release(cddm); /* calc disps */ @@ -863,10 +904,11 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl /* create subsurf DM from original mesh at high level */ cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv); + highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, TRUE); + ss = ((CCGDerivedMesh*)highdm)->ss; /* create multires DM from original mesh at low level */ - lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple); + lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple, TRUE); cddm->release(cddm); /* copy subsurf grids and replace them with low displaced grids */ @@ -892,7 +934,6 @@ static void multires_subdivide(MultiresModifierData *mmd, Object *ob, int totlvl lowdm->release(lowdm); /* subsurf higher levels again with displaced data */ - ss = ((CCGDerivedMesh *)highdm)->ss; ccgSubSurf_updateFromFaces(ss, lvl, NULL, 0); ccgSubSurf_updateLevels(ss, lvl, NULL, 0); @@ -952,6 +993,7 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm CCGKey key; MPoly *mpoly = me->mpoly; MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); + GridPaintMask *grid_paint_mask = NULL; int *gridOffset; int i, k, /*numGrids, */ gridSize, dGridSize, dSkip; int totloop, totpoly; @@ -985,6 +1027,10 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm dGridSize = multires_side_tot[totlvl]; dSkip = (dGridSize - 1) / (gridSize - 1); + /* multires paint masks */ + if (key.has_mask) + grid_paint_mask = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK); + k = 0; /*current loop/mdisp index within the mloop array*/ #pragma omp parallel for private(i) if (totloop*gridSize*gridSize >= CCG_OMP_LIMIT) @@ -994,6 +1040,7 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm int S, x, y, gIndex = gridOffset[i]; for (S = 0; S < numVerts; ++S, ++gIndex, ++k) { + GridPaintMask *gpm = grid_paint_mask ? &grid_paint_mask[gIndex] : NULL; MDisps *mdisp = &mdisps[mpoly[i].loopstart + S]; CCGElem *grid = gridData[gIndex]; CCGElem *subgrid = subGridData[gIndex]; @@ -1008,13 +1055,22 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm dispgrid = mdisp->disps; + /* if needed, reallocate multires paint mask */ + if (gpm && op == CALC_DISPLACEMENTS) { + if (gpm->level < key.level) { + gpm->level = key.level; + MEM_freeN(gpm->data); + gpm->data = MEM_callocN(sizeof(float) * key.grid_area, "gpm.data"); + } + } + for (y = 0; y < gridSize; y++) { for (x = 0; x < gridSize; x++) { float *co = CCG_grid_elem_co(&key, grid, x, y); float *sco = CCG_grid_elem_co(&key, subgrid, x, y); float *no = CCG_grid_elem_no(&key, subgrid, x, y); - float *data = dispgrid[dGridSize * y * dSkip + x * dSkip]; - float mat[3][3], tx[3], ty[3], disp[3], d[3]; + float *data = dispgrid[dGridSize*y*dSkip + x*dSkip]; + float mat[3][3], tx[3], ty[3], disp[3], d[3], mask; /* construct tangent space matrix */ grid_tangent(&key, x, y, 0, subGridData[gIndex], tx); @@ -1051,11 +1107,31 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm add_v3_v3(data, d); break; } + + if (gpm) { + switch (op) { + case APPLY_DISPLACEMENTS: + /* Copy mask from gpm to DM */ + *CCG_grid_elem_mask(&key, grid, x, y) = + paint_grid_paint_mask(gpm, key.level, x, y); + break; + case CALC_DISPLACEMENTS: + /* Copy mask from DM to gpm */ + mask = *CCG_grid_elem_mask(&key, grid, x, y); + gpm->data[y * gridSize + x] = CLAMPIS(mask, 0, 1); + break; + case ADD_DISPLACEMENTS: + /* Add mask displacement to gpm */ + gpm->data[y * gridSize + x] += + *CCG_grid_elem_mask(&key, grid, x, y); + break; + } + } } } } } - + if (op == APPLY_DISPLACEMENTS) { ccgSubSurf_stitchFaces(ccgdm->ss, 0, NULL, 0); ccgSubSurf_updateNormals(ccgdm->ss, NULL, 0); @@ -1094,10 +1170,11 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm) else cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv); + highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, TRUE); + ss = ((CCGDerivedMesh*)highdm)->ss; /* create multires DM from original mesh and displacements */ - lowdm = multires_dm_create_local(ob, cddm, lvl, totlvl, mmd->simple); + lowdm = multires_dm_create_local(ob, cddm, lvl, totlvl, mmd->simple, TRUE); cddm->release(cddm); /* gather grid data */ @@ -1122,7 +1199,7 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm) /* write difference of subsurf and displaced low level into high subsurf */ for (j = 0; j < lowGridSize*lowGridSize; ++j) { - sub_v3_v3v3(CCG_elem_offset_co(&lowGridKey, diffGrid, j), + sub_v4_v4v4(CCG_elem_offset_co(&lowGridKey, diffGrid, j), CCG_elem_offset_co(&lowGridKey, gridData[i], j), CCG_elem_offset_co(&lowGridKey, lowGridData[i], j)); } @@ -1135,7 +1212,6 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm) lowdm->release(lowdm); /* subsurf higher levels again with difference of coordinates */ - ss = ((CCGDerivedMesh *)highdm)->ss; ccgSubSurf_updateFromFaces(ss, lvl, NULL, 0); ccgSubSurf_updateLevels(ss, lvl, NULL, 0); @@ -1155,7 +1231,7 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm) else cddm = CDDM_from_mesh(me, NULL); DM_set_only_copy(cddm, CD_MASK_BAREMESH); - subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv); + subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, TRUE); cddm->release(cddm); multiresModifier_disp_run(dm, me, NULL, CALC_DISPLACEMENTS, subdm->getGridData(subdm), mmd->totlvl); @@ -1218,10 +1294,10 @@ void multires_set_space(DerivedMesh *dm, Object *ob, int from, int to) } totlvl = mmd->totlvl; - ccgdm = multires_dm_create_local(ob, dm, totlvl, totlvl, mmd->simple); + ccgdm = multires_dm_create_local(ob, dm, totlvl, totlvl, mmd->simple, FALSE); subsurf = subsurf_dm_create_local(ob, dm, totlvl, - mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges, mmd->flags & eMultiresModifierFlag_PlainUv); + mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges, mmd->flags & eMultiresModifierFlag_PlainUv, 0); numGrids = subsurf->getNumGrids(subsurf); gridSize = subsurf->getGridSize(subsurf); @@ -1362,8 +1438,9 @@ DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm, return dm; result = subsurf_dm_create_local(ob, dm, lvl, - mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges, - mmd->flags & eMultiresModifierFlag_PlainUv); + mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges, + mmd->flags & eMultiresModifierFlag_PlainUv, + flags & MULTIRES_ALLOC_PAINT_MASK); if (!(flags & MULTIRES_USE_LOCAL_MMD)) { ccgdm = (CCGDerivedMesh *)result; @@ -2101,7 +2178,7 @@ static void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3]) MEM_freeN(vertCos); /* scaled ccgDM for tangent space of object with applied scale */ - dm = subsurf_dm_create_local(ob, cddm, high_mmd.totlvl, high_mmd.simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv); + dm = subsurf_dm_create_local(ob, cddm, high_mmd.totlvl, high_mmd.simple, 0, mmd->flags & eMultiresModifierFlag_PlainUv, 0); cddm->release(cddm); /*numGrids = dm->getNumGrids(dm);*/ /*UNUSED*/ diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 0a36ccbf8e5..c6b3a8d3aba 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -111,7 +111,9 @@ static void arena_release(CCGAllocatorHDL a) typedef enum { CCG_USE_AGING = 1, CCG_USE_ARENA = 2, - CCG_CALC_NORMALS = 4 + CCG_CALC_NORMALS = 4, + /* add an extra four bytes for a mask layer */ + CCG_ALLOC_MASK = 8 } CCGFlags; static CCGSubSurf *_getSubSurf(CCGSubSurf *prevSS, int subdivLevels, @@ -152,6 +154,8 @@ static CCGSubSurf *_getSubSurf(CCGSubSurf *prevSS, int subdivLevels, normalOffset += sizeof(float) * numLayers; if(flags & CCG_CALC_NORMALS) ifc.vertDataSize += sizeof(float) * 3; + if(flags & CCG_ALLOC_MASK) + ifc.vertDataSize += sizeof(float); if (useArena) { CCGAllocatorIFC allocatorIFC; @@ -172,6 +176,12 @@ static CCGSubSurf *_getSubSurf(CCGSubSurf *prevSS, int subdivLevels, ccgSubSurf_setUseAgeCounts(ccgSS, 1, 8, 8, 8); } + if (flags & CCG_ALLOC_MASK) { + normalOffset += sizeof(float); + /* mask is allocated after regular layers */ + ccgSubSurf_setAllocMask(ccgSS, 1, sizeof(float) * numLayers); + } + if (flags & CCG_CALC_NORMALS) ccgSubSurf_setCalcVertexNormals(ccgSS, 1, normalOffset); else @@ -3496,12 +3506,17 @@ struct DerivedMesh *subsurf_make_derived_from_derived( useSubsurfUv, dm); } else { + CCGFlags ccg_flags = CCG_USE_ARENA | CCG_CALC_NORMALS; + if (smd->mCache && (flags & SUBSURF_IS_FINAL_CALC)) { ccgSubSurf_free(smd->mCache); smd->mCache = NULL; } - ss = _getSubSurf(NULL, levels, 3, CCG_USE_ARENA | CCG_CALC_NORMALS); + if (flags & SUBSURF_ALLOC_PAINT_MASK) + ccg_flags |= CCG_ALLOC_MASK; + + ss = _getSubSurf(NULL, levels, 3, ccg_flags); ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple); result = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm); @@ -3510,6 +3525,9 @@ struct DerivedMesh *subsurf_make_derived_from_derived( smd->mCache = ss; else result->freeSS = 1; + + if (flags & SUBSURF_ALLOC_PAINT_MASK) + ccgSubSurf_setNumLayers(ss, 4); } } diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c index ee2c7c82c42..13028953c1c 100644 --- a/source/blender/modifiers/intern/MOD_multires.c +++ b/source/blender/modifiers/intern/MOD_multires.c @@ -86,6 +86,7 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, } } + flags = MULTIRES_ALLOC_PAINT_MASK; if (useRenderParams) flags |= MULTIRES_USE_RENDER_PARAMS; |